package cn.sangyy.gift.service.impl;

import cn.sangyy.gift.common.util.IdName;
import cn.sangyy.gift.common.util.PageList;
import cn.sangyy.gift.doc.SpuGiftDoc;
import cn.sangyy.gift.exception.BusinessException;
import cn.sangyy.gift.query.SpuGiftQuery;
import cn.sangyy.gift.service.ISpuGiftService;
import com.alibaba.fastjson.JSON;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;

/**
 * @author SangYY
 * @date: 2023/04/08/11:18
 */
@Service
public class SpuGiftServiceImpl implements ISpuGiftService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public PageList<SpuGiftDoc> search(SpuGiftQuery query) {
        try {
            String keyword = query.getKeyword();
            Integer page = query.getPage();
            Integer rows = query.getRows();
            //准备request
            SearchRequest request = new SearchRequest("gift");
            //DSL语句
            request.source().query(QueryBuilders.multiMatchQuery(keyword,"name","tenantName","brandName","typeName"));
            //高亮
            request.source().highlighter(new HighlightBuilder()
                    .field("name").field("brandName").field("typeName").field("tenantName")
                    .preTags("<font style='color:red'><b>").postTags("</b></font>")
                    .requireFieldMatch(false));
            //分页
            request.source().from((page-1)*rows).size(rows);
            //排序

            //聚合（品牌、类型、租户）
            buildAggregation(request);
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            return handleResponse(response);
        } catch (IOException e) {
            throw new BusinessException("es搜索异常，请联系管理员",203);
        }
    }
    //构建聚合
    private void buildAggregation(SearchRequest request) {
        request.source().aggregation(AggregationBuilders
                .terms("brandIdAgg")
                .field("brandId")
                .size(100)
                .subAggregation(AggregationBuilders
                        .terms("brandNameAgg")
                        .field("brandName.keyword")
                        .size(100))
        );
        request.source().aggregation(AggregationBuilders
                .terms("typeIdAgg")
                .field("typeId")
                .size(100)
                .subAggregation(AggregationBuilders
                        .terms("typeNameAgg")
                        .field("typeName.keyword")
                        .size(100))
        );
        request.source().aggregation(AggregationBuilders
                .terms("tenantIdAgg")
                .field("tenantId")
                .size(100)
                .subAggregation(AggregationBuilders
                        .terms("tenantNameAgg")
                        .field("tenantName.keyword")
                        .size(100))
        );
    }
    //统一结果处理
    private PageList<SpuGiftDoc> handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        long totalHits = searchHits.getTotalHits();
        SearchHit[] hits = searchHits.getHits();
        ArrayList<SpuGiftDoc> result = new ArrayList<>();
        for (SearchHit hit : hits) {
            SpuGiftDoc spuGiftDoc;
            //得到文档resource
            String json = hit.getSourceAsString();
            spuGiftDoc = JSON.parseObject(json, SpuGiftDoc.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(!CollectionUtils.isEmpty(highlightFields)){
                HighlightField highlightField1 = highlightFields.get("name");
                HighlightField highlightField2 = highlightFields.get("brandName");
                HighlightField highlightField3 = highlightFields.get("typeName");
                HighlightField highlightField4 = highlightFields.get("tenantName");
                if(highlightField1 != null){
                    String name = highlightField1.getFragments()[0].string();
                    spuGiftDoc.setName(name);
                }
                if(highlightField2 != null){
                    String brandName = highlightField2.getFragments()[0].string();
                    spuGiftDoc.setBrandName(brandName);
                }
                if(highlightField3 != null){
                    String typeName = highlightField3.getFragments()[0].string();
                    spuGiftDoc.setTypeName(typeName);
                }
                if(highlightField4 != null){
                    String tenantName = highlightField4.getFragments()[0].string();
                    spuGiftDoc.setTenantName(tenantName);
                }
            }
            result.add(spuGiftDoc);
        }
        Aggregations aggregations = response.getAggregations();
        Map<String, List<IdName>> map = getMapByAgg(aggregations);
        PageList<SpuGiftDoc> pageList = new PageList<>();
        pageList.setRows(result);
        pageList.setAggsMap(map);
        return pageList;
    }

    private Map<String,List<IdName>> getMapByAgg(Aggregations aggregations){
        Map<String,List<IdName>> result = new HashMap<>();
        Map<String, Aggregation> map1 = aggregations.getAsMap();
        Set<Map.Entry<String, Aggregation>> entries1 = map1.entrySet();
        
        for (Map.Entry<String, Aggregation> e : entries1) {
            Terms longTerms = (Terms) e.getValue();
            List<? extends Terms.Bucket> buckets1 = longTerms.getBuckets();
            List<IdName> idNames = new ArrayList<>();
            for (Terms.Bucket b : buckets1) {
                IdName idName = new IdName();
                String id = b.getKeyAsString();
                idName.setId(Long.valueOf(id));
                Aggregations aggregations1 = b.getAggregations();
                Map<String, Aggregation> map2 = aggregations1.getAsMap();
                Set<Map.Entry<String, Aggregation>> entries2 = map2.entrySet();
                Iterator<Map.Entry<String, Aggregation>> iterator = entries2.iterator();
                Map.Entry<String, Aggregation> entry = iterator.next();
                Terms StringTerms = (Terms) entry.getValue();
                List<? extends Terms.Bucket> buckets2 = StringTerms.getBuckets();
                if (buckets2.size() > 0) {
                    String name = buckets2.get(0).getKeyAsString();
                    idName.setName(name);
                }
                idNames.add(idName);
                System.out.println(idName);
            }
            result.put(e.getKey(), idNames);
        }
        return result;
    }
}
